#!/usr/bin/env python
# -*- coding: utf-8 -*-

import json
import threading
from common.utils import LogUtil
from web_server.models.service_info import ServiceInfo
from web_server.models.zmq_client import ZmqClient
from common.webrtc_errno import WebRTCErrno

logger = LogUtil.get_logger(__name__)

class DeviceClient:
    def __init__(self, service_info: ServiceInfo, zmq_syn_context, zmq_aio_context):
        self.service_info = service_info
        self.__device_info_map = {}
        self.__lock = threading.Lock()
        self.__zmq_client = None
        self.__need_reload = True
        self.__zmq_client = ZmqClient(service_info, zmq_syn_context, zmq_aio_context)

    def __del__(self):
        self.destroy()

    def destroy(self):
        with self.__lock:
            self.__device_info_map.clear()
            if self.__zmq_client:
                self.__zmq_client.destroy()
                self.__zmq_client = None

    def get_device_info_map(self):
        with self.__lock:
            return self.__device_info_map

    def update_device_info_map(self, force_reload = False):
        with self.__lock:
            response = None
            response = self.__zmq_client.recv_multipart()
            if response is not None and response[0] == b'reload_devices':
                self.__device_info_map.clear()
                device_info_list = json.loads(response[1].decode('utf-8'))
                for device_info in device_info_list:
                    self.__device_info_map[device_info['sn']] = device_info
                # 设备列表已更新，无需强制加载或者重新加载
                self.__need_reload = False
                return True
            
            if force_reload is True:
                self.__need_reload = True
            if self.__need_reload is False:
                return False
            request = {'api': 'load_devices'}
            if self.__zmq_client.send_json(request) is False:
                return False    
            response = self.__zmq_client.recv_json()
            if response is None:
                return False
            # 加载设备列表成功, 不再需要重新加载
            self.__need_reload = False
            self.__device_info_map.clear()
            for device_info in response['result']:
                self.__device_info_map[device_info['sn']] = device_info
            return True

    async def handle_webrtc_offer(self, data: dict):
        """处理设备服务器offer

        Args:
            data (dict): webrtc offer信令数据

        Returns:
            dict: 处理结果
        """
        webrtc_error = {
            'type': 'webrtc_error',
            'data': {
                'signal_syn_seq': data['signal_ack_seq'],
                'signal_ack_seq': data['signal_syn_seq'] + 1,
                'client_id': data['client_id'],
                'device_sn': data['device_sn'],
                'source': 'webrtc_offer',
                'errnum': WebRTCErrno.ESIGSVR.value,
                'errmsg': 'Failed to forward webrtc offer'
            }
        }
        with self.__lock:
            device_info = self.__device_info_map.get(data['device_sn'], None)
            if device_info is None:
                logger.error(f"failed to forward webrtc offer: device info not found")
                return webrtc_error
            message = { 'type': 'webrtc_offer', 'data': data }
            if await self.__zmq_client.async_send_json(message) is False:
                logger.error(f"failed to send webrtc offer: send message error")
                webrtc_error['data']['errnum'] = WebRTCErrno.ETRANSPORT.value
                webrtc_error['data']['errmsg'] = 'Failed to send webrtc offer'
                return webrtc_error
            response = await self.__zmq_client.async_recv_json()
            if response is None:
                logger.error(f"failed to recv webrtc answer: recv message error")
                webrtc_error['data']['errnum'] = WebRTCErrno.ETRANSPORT.value
                webrtc_error['data']['errmsg'] = 'Failed to recv webrtc answer'
                return webrtc_error
            if response['type'] == 'webrtc_error':
                logger.error(f"failed to exchange webrtc offer/answer: peer error")
                webrtc_error['data']['errnum'] = response['data']['errnum']
                webrtc_error['data']['errmsg'] = response['data']['errmsg']
                return webrtc_error
            if response['type'] != 'webrtc_answer':
                logger.error(f"failed to exchange webrtc offer/answer: type error")
                webrtc_error['data']['errnum'] = WebRTCErrno.ESTATE.value
                webrtc_error['data']['errmsg'] = 'Failed to exchange webrtc offer/answer'
                return webrtc_error
            return response

    async def handle_webrtc_candidate(self, data: dict):
        """处理ICE候选

        Args:
            data (dict): webrtc candidate信令数据

        Returns:
            dict: 处理结果
        """
        webrtc_error = {
            'type': 'webrtc_error',
            'data': {
                'signal_syn_seq': data['signal_ack_seq'],
                'signal_ack_seq': data['signal_syn_seq'] + 1,
                'client_id': data['client_id'],
                'device_sn': data['device_sn'],
                'source': 'webrtc_candidate',
                'errnum': WebRTCErrno.ESIGSVR.value,
                'errmsg': 'Failed to forward webrtc candidate'
            }
        }
        with self.__lock:
            device_info = self.__device_info_map.get(data['device_sn'], None)
            if device_info is None:
                logger.error(f"failed to forward webrtc candidate: device info not found")
                return webrtc_error
            message = { 'type': 'webrtc_candidate', 'data': data }
            if await self.__zmq_client.async_send_json(message) is False:
                logger.error(f"failed to send webrtc candidate: send message error")
                webrtc_error['data']['errnum'] = WebRTCErrno.ETRANSPORT.value
                webrtc_error['data']['errmsg'] = 'Failed to send webrtc candidate'
                return webrtc_error
            response = await self.__zmq_client.async_recv_json()
            if response is None:
                logger.error(f"failed to recv webrtc candidate: recv message error")
                webrtc_error['data']['errnum'] = WebRTCErrno.ETRANSPORT.value
                webrtc_error['data']['errmsg'] = 'Failed to recv webrtc candidate'
                return webrtc_error
            if response['type'] == 'webrtc_error':
                logger.error(f"failed to exchange webrtc candidate: peer error")
                webrtc_error['data']['errnum'] = response['data']['errnum']
                webrtc_error['data']['errmsg'] = response['data']['errmsg']
                return webrtc_error
            if response['type'] != 'webrtc_candidate':
                logger.error(f"failed to exchange webrtc candidate: type error")
                webrtc_error['data']['errnum'] = WebRTCErrno.ESTATE.value
                webrtc_error['data']['errmsg'] = 'Failed to exchange webrtc candidate'
                return webrtc_error
            return response

    async def handle_webrtc_disconnect(self, data: dict):
        """处理WebRTC断开连接

        Args:
            data (dict): webrtc disconnect信令数据

        Returns:
            dict: 处理结果
        """
        webrtc_error = {
            'type': 'webrtc_error',
            'data': {
                'signal_syn_seq': data['signal_ack_seq'],
                'signal_ack_seq': data['signal_syn_seq'] + 1,
                'client_id': data['client_id'],
                'device_sn': data['device_sn'],
                'source': 'webrtc_disconnect',
                'errnum': WebRTCErrno.ESIGSVR.value,
                'errmsg': 'Failed to forward webrtc disconnect'
            }
        }
        with self.__lock:
            device_info = self.__device_info_map.get(data['device_sn'], None)
            if device_info is None:
                logger.error(f"failed to forward webrtc disconnect: device info not found")
                return webrtc_error
            message = { 'type': 'webrtc_disconnect', 'data': data }
            if await self.__zmq_client.async_send_json(message) is False:
                logger.error(f"failed to send webrtc disconnect: send message error")
                webrtc_error['data']['errnum'] = WebRTCErrno.ETRANSPORT.value
                webrtc_error['data']['errmsg'] = 'Failed to send webrtc disconnect'
                return webrtc_error
            response = await self.__zmq_client.async_recv_json()
            if response is None:
                logger.error(f"failed to recv webrtc disconnect: recv message error")
                webrtc_error['data']['errnum'] = WebRTCErrno.ETRANSPORT.value
                webrtc_error['data']['errmsg'] = 'Failed to recv webrtc disconnect'
                return webrtc_error
            if response['type'] == 'webrtc_error':
                logger.error(f"failed to exchange webrtc disconnect: peer error")
                webrtc_error['data']['errnum'] = response['data']['errnum']
                webrtc_error['data']['errmsg'] = response['data']['errmsg']
                return webrtc_error
            if response['type'] != 'webrtc_disconnect':
                logger.error(f"failed to exchange webrtc disconnect: type error")
                webrtc_error['data']['errnum'] = WebRTCErrno.ESTATE.value
                webrtc_error['data']['errmsg'] = 'Failed to exchange webrtc disconnect'
                return webrtc_error
            return response

    def capture_screen(self, sn: str, filename: str):
        """捕获屏幕

        Args:
            sn (str): 设备SN
            filename (str): 文件名

        Returns:
            bool: 捕获结果
        """
        request = {
            'api': 'capture_screen',
            'sn': sn,
            'filename': filename,
        }
        if self.__zmq_client.send_json(request) is False:
            return None
        response = self.__zmq_client.recv_json()
        if response is None:
            return None
        return response['result']
